package com.wei.czz.framework.common.controller;

import java.util.*;

import com.wei.czz.common.annotation.Auth;
import com.wei.czz.common.annotation.Resubmit;
import com.wei.czz.common.dto.common.limitConfig.LimitConfigDto;
import com.wei.czz.common.dto.common.limitConfig.LimitConfigEnumsDto;
import com.wei.czz.common.dto.common.limitConfig.LimitStatsDto;
import com.wei.czz.common.enums.common.limitConfig.LimitConfigTypeEnum;
import com.wei.czz.common.enums.common.limitConfig.LimitConfigUnitEnum;
import com.wei.czz.common.jsr303.group.OrderSearch;
import com.wei.czz.common.jsr303.group.Save;
import com.wei.czz.common.jsr303.group.Update;
import com.wei.czz.common.property.BatchProperty;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.Result;
import com.wei.czz.common.vo.common.limitConfig.LimitConfigVo;
import com.wei.czz.common.vo.common.UpdateStatusVo;
import com.wei.czz.common.vo.common.limitConfig.LimitConfigFormVo;
import com.wei.czz.framework.common.manager.LimitConfigManager;
import com.wei.czz.framework.common.service.LimitConfigService;
import com.wei.czz.framework.common.helper.LimitHelper;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2023-02-16 21:38:02
 * className: LimitConfigController 限流配置请求接口类
 * version: 1.0
 * description:
 */
@RestController
@RequestMapping("/sys/limit-config")
@AllArgsConstructor
public class LimitConfigController {

    private static final Logger log = LoggerFactory.getLogger(LimitConfigController.class);

    private final BatchProperty batchProperty;

    private final LimitConfigManager limitConfigManager;

    private final LimitConfigService limitConfigService;

    private final LimitHelper limitHelper;

    /**
     * 保存限流配置数据接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-限流管理页面-新增/修改限流配置弹出框调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id            限流配置主键
     * @param limitConfigVo 限流配置参数对象
     */
    @Resubmit(spEL = "'saveLimitConfig' + #userPo.userId", message = "保存限流配置")
    @RequestMapping("/save")
    @Auth(permit = "limit:config:save")
    public Result<Object> saveLimitConfig(@RequestParam(value = "id", required = false) Long id,
                                          @Validated(Save.class) @RequestBody LimitConfigVo limitConfigVo) {
        log.info("开始保存限流配置数据业务。id={} {}", id, limitConfigVo);
        if (Objects.isNull(LimitConfigTypeEnum.get(limitConfigVo.getType()))) {
            log.info("保存限流配置数据接口，限流类型参数错误");
            return Result.paramFail();
        }
        if (Objects.isNull(LimitConfigUnitEnum.get(limitConfigVo.getTimeType()))) {
            log.info("保存限流配置数据接口，时间单位参数错误");
            return Result.paramFail();
        }

        limitConfigManager.saveLimit(id, limitConfigVo);

        log.info("保存限流配置数据业务结束");
        return Result.success();
    }

    /**
     * 分页获取限流配置接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-限流管理页面调用
     *
     * @param limitConfigFormVo 限流配置参数对象
     * @return 限流配置分页数据
     */
    @Resubmit(
            spEL = "'getLimitConfigPageList' + #userPo.userId + '-' + #limitConfigFormVo",
            message = "分页获取限流配置"
    )
    @PostMapping("/page/list")
    @Auth(permit = "limit:config:list")
    public Result<PageDto<LimitConfigDto>> getLimitConfigPageList(
            @Validated(OrderSearch.class) @RequestBody LimitConfigFormVo limitConfigFormVo){
        log.info("开始分页获取限流配置业务。{}", limitConfigFormVo);

        PageDto<LimitConfigDto> page = limitConfigManager.getLimitConfigPageList(limitConfigFormVo);

        log.info("分页获取限流配置业务结束");
        return Result.success(page);
    }

    /**
     * 获取限流配置枚举数据接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-限流管理页面调用
     *
     * @return 限流配置枚举数据
     */
    @GetMapping("/page/param")
    @Auth(permit = "limit:config:list")
    public Result<Object> getEnums() {
        log.info("开始获取限流配置枚举数据业务");

        LimitConfigEnumsDto limitConfigEnumsDto = limitConfigManager.getEnums();

        log.info("获取限流配置枚举数据业务结束");
        return Result.success(limitConfigEnumsDto);
    }

    /**
     * 校验限流配置接口
     * 校验是否存在相同配置且可用的历史限流配置数据
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面调用
     *  2、浏览器-后台管理页面-限流管理页面-新增/修改限流配置弹出框调用
     *
     * @param requestKey 接口路径
     * @param type       限流类型
     * @return 校验结果
     */
    @GetMapping("/check")
    @Auth(permit = { "limit:config:save", "limit:config:list" })
    public Result<Long> checkLimitConfig(@RequestParam("requestKey") String requestKey,
                                         @RequestParam("type") Integer type) {
        log.info("开始校验限流配置业务。requestKey={} type={}", requestKey, type);

        Long id = limitConfigManager.checkLimitConfig(requestKey, type);

        log.info("校验限流配置业务结束");
        return Result.success(id);
    }

    /**
     * 获取限流统计数据接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-限流管理页面-查看限流配置弹出框调用
     *
     * @param requestKey 接口路径
     * @param type       限流类型
     * @return 限流统计数据
     */
    @GetMapping("/stats")
    @Auth(permit = "limit:config:get")
    public Result<LimitStatsDto> getLimitStats(@RequestParam("requestKey") String requestKey,
                                               @RequestParam("type") Integer type) {
        log.info("开始获取限流统计数据业务。requestKey={} type={}", requestKey, type);
        if (Objects.isNull(LimitConfigTypeEnum.get(type))) {
            log.info("获取限流统计数据接口，限流类型参数错误");
            return Result.paramFail();
        }

        LimitStatsDto limitStatsDto = limitHelper.getLimitStats(requestKey, type);

        log.info("获取限流统计数据业务结束");
        return Result.success(limitStatsDto);
    }

    /**
     * 修改限流配置数据接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-限流管理页面-新增/修改限流配置弹出框调用
     * <p>
     * 此接口会校验是否重复提交
     * @param limitConfigVo 限流配置参数对象
     */
    @Resubmit(spEL = "'updateLimitConfig' + #userPo.userId", message = "修改限流配置")
    @PostMapping("/update")
    @Auth(permit = "limit:config:update")
    public Result<Object> updateLimitConfig(@Validated(Update.class) @RequestBody LimitConfigVo limitConfigVo) {
        log.info("开始修改限流配置数据业务。{}", limitConfigVo);
        if (Objects.isNull(LimitConfigTypeEnum.get(limitConfigVo.getType()))) {
            log.info("修改限流配置数据接口，限流类型参数错误");
            return Result.paramFail();
        }
        if (Objects.isNull(LimitConfigUnitEnum.get(limitConfigVo.getTimeType()))) {
            log.info("修改限流配置数据接口，时间单位参数错误");
            return Result.paramFail();
        }

        limitConfigManager.updateLimitConfig(limitConfigVo);

        log.info("修改限流配置数据业务结束");
        return Result.success();
    }

    /**
     * 修改限流配置状态接口
     * @param updateStatusVo 参数对象
     * @return 结果
     */
    @Resubmit(spEL = "'updateLimitConfigStatus' + #userPo.userId", message = "修改限流配置状态")
    @PostMapping("/update/status")
    @Auth(permit = "limit:config:update")
    public Result<List<String>> updateLimitConfigStatus(@Validated @RequestBody UpdateStatusVo updateStatusVo) {
        log.info("开始修改限流配置状态业务。{}", updateStatusVo);

        List<Long> paramsIdList = updateStatusVo.getIdList();
        if (batchProperty.getMaxSize() < paramsIdList.size()) {
            log.warn("修改限流配置状态数量超限。batch.size={} size={}", batchProperty.getMaxSize(), paramsIdList.size());
            return Result.clientFail("一次修改限流配置状态，最多允许同时修改" + batchProperty.getMaxSize() + "个配置");
        }

        List<String> idList = limitConfigManager.updateLimitConfigStatus(updateStatusVo);

        log.info("修改限流配置状态业务结束");
        return Result.success(idList);
    }

    /**
     * 删除限流配置接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-限流管理页面调用
     *  <p>
     * 此接口会校验是否重复提交
     * @param idList 主键列表
     * @return 结果
     */
    @Resubmit(spEL = "'deleteLimitConfig' + #userPo.userId", message = "删除限流配置")
    @DeleteMapping("/batch/delete")
    @Auth(permit = "limit:config:delete")
    public Result<Object> deleteLimitConfig(@RequestBody List<Long> idList) {
        log.info("开始批量删除限流配置数据业务。idList={}", idList);

        if (batchProperty.getMaxSize() < idList.size()) {
            log.info("删除限流配置数量超限");
            return Result.clientFail("一次删除限流配置，最多允许同时删除" + batchProperty.getMaxSize() + "个配置");
        }

        limitConfigManager.deleteLimitConfig(idList);

        log.info("批量删除限流配置数据业务结束");
        return Result.success();
    }

}
